#pragma once

#include "util.hpp"
#include "config.hpp"
#include <unordered_map>
#include <pthread.h>
#include <iostream>

namespace cloud
{
    struct BackupInfo
    {
        void NewBackupInfo(const std::string &realpath)
        {

            FileUtil fu(realpath);

            if (fu.Exists() == false)
            {
                std::cerr << "New Backup Info : 文件不存在" << std::endl;
                return;
            }
            Config *config = Config::GetInstance();
            std::string packdir = config->GetPackDir();
            std::string packsuffix = config->GetPackFileSuffix();
            std::string download_prefix = config->GetDownloadPrefix();

            pack_flag = false;
            fsize = fu.FileSize();
            atime = fu.LastATime();
            mtime = fu.LastMTime();
            real_path = realpath;

            // 实际存储路径: ./backdir/a.txt   压缩存储路径: ./packdir/a.txt.lz
            pack_path = packdir + fu.FileName() + packsuffix;
            // 实际存储路径: ./backdir/a.txt   url: /download/a.txt
            url = download_prefix + fu.FileName();
        }

        bool pack_flag;        // 是否被压缩
        size_t fsize;          // 文件大小
        time_t atime;          // 最后访问时间
        time_t mtime;          // 最后修改时间
        std::string real_path; // 实际存储路径
        std::string pack_path; // 压缩包存储路径名称
        std::string url;       // 请求的资源路径
    };

    class DataManager
    {
    public:
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_rwlock, NULL);
            InitLoad();
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }

        bool Storage()
        {
            // 每次数据新增或修改，都要重新持久化，避免数据丢失

            // 1.获取所有数据

            // 2.添加到json value中

            std::vector<BackupInfo> arry;
            GetAll(&arry);

            Json::Value root;
            for (int i = 0; i < arry.size(); i++)
            {
                Json::Value item;
                item["pack_flag"] = arry[i].pack_flag;
                item["fsize"] = (Json::Int64)arry[i].fsize;
                item["atime"] = (Json::Int64)arry[i].atime;
                item["mtime"] = (Json::Int64)arry[i].mtime;
                item["real_path"] = arry[i].real_path;
                item["pack_path"] = arry[i].pack_path;
                item["url"] = arry[i].url;

                root.append(item);
            }
            // 3.序列化

            std::string body;
            JsonUtil::Serialize(root, &body);

            // 4.写文件
            FileUtil fu(_backup_file);
            fu.SetContent(body);

            return true;
        }

        bool InitLoad()
        {
            // 初始化加载，每次系统重启都要加载以前的数据
            
            //1.将数据文件的数据读取
            FileUtil fu(_backup_file);
            if(fu.Exists() == false)
            {
                std::cerr << "InitLoad error can not find file" << std::endl;
                std::ofstream ofs(_backup_file,std::ios::binary);
                ofs.close();
                std::cerr << "InitLoad create file" << std::endl;
            }
            std::string body;
            fu.GetContent(&body);

            //2.反序列化
            Json::Value root;
            JsonUtil::UnSerialize(body,&root);

 
            //3.将反序列化得到的Json::Value中的数据添加到table中

            for(int i = 0;i<root.size();i++)
            {
                BackupInfo info;

                info.pack_flag = root[i]["pack_flag"].asBool();
                info.fsize = root[i]["fsize"].asInt64();
                info.atime = root[i]["atime"].asInt64();
                info.mtime = root[i]["mtime"].asInt64();
                info.real_path = root[i]["real_path"].asString();
                info.pack_path = root[i]["pack_path"].asString();
                info.url = root[i]["url"].asString();

                Insert(info);

            }

            return true;
        }

        bool Insert(const BackupInfo &info)
        {
            // 新增
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);

            Storage();
            return true;
        }

        bool Update(const BackupInfo &info)
        {
            // 修改
            pthread_rwlock_wrlock(&_rwlock);
            _table[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }

        bool GetOneByUrl(const std::string &url, BackupInfo *info)
        {
            // 根据某个url获取请求的文件信息
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.find(url);
            if (it == _table.end())
            {
                return false;
            }
            *info = it->second;
            pthread_rwlock_unlock(&_rwlock);

            return true;
        }

        bool GetOneByRealpath(const std::string &path, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&_rwlock);

            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                if (it->second.real_path == path)
                {
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwlock);

                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);

            return false;
        }

        bool GetAll(std::vector<BackupInfo> *arry)
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                arry->push_back(it->second);
            }

            pthread_rwlock_unlock(&_rwlock);

            return true;
        }

    private:
        std::string _backup_file;                           // 持久化存储文件
        std::unordered_map<std::string, BackupInfo> _table; // 以哈希存储

        pthread_rwlock_t _rwlock; // 读写锁：读共享，写互斥
    };

}


